/**
 * This file is part of CommaTuner.
 * Copyright 2011 Gabriel G Mendonça (gabrielgmendonca@gmail.com)
 * 
 * CommaTuner is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * CommaTuner is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with CommaTuner.  If not, see <http://www.gnu.org/licenses/>.
 */

package br.mendonca.audio.analysis;

/**
 * A simple representation of a musical pitch.
 * 
 * @author gmendonca
 */
public class Pitch {

	private enum Note {
		C, Cs, D, Ds, E, F, Fs, G, Gs, A, As, B;

		@Override
		public String toString() {
			return name().replace('s', '#');
		}
	}

	/** The fundamental frequency. E.g, 440Hz for A4 */
	public float frequency;

	/** The frequency resolution given by (Sample Rate / Buffer Size). */
	public float precision;

	/**
	 * Constructor.
	 * 
	 * @param frequency
	 *            The fundamental frequency.
	 * @param precision
	 *            The frequency resolution.
	 */
	public Pitch(float frequency, float precision) {
		this.frequency = frequency;
		this.precision = precision;
	}

	/**
	 * Gives the fundamental frequency mapping to linear pitch space as in MIDI
	 * protocol. E.g., 440Hz is mapped to 69.
	 * 
	 * @return The fundamental frequency in linear pitch space.
	 */
	public float toLinearSpace() {
		double linear = 69.0 + 12.0 * Math.log(frequency / 440.0) / Math.log(2);
		return (float) Math.max(linear, 0.0);
	}

	/**
	 * Gives the distance from the pitch to closest note.
	 * 
	 * @return The distance in cents.
	 */
	public int getError() {
		return Math.round((toLinearSpace() % 1.0f) * 100.0f);
	}

	/**
	 * Gives the fundamental frequency using scientific pitch notation. E.g.,
	 * 440Hz is mapped to A4.
	 * 
	 * @return The fundamental frequency in scientific pitch notation.
	 */
	public String toScientificNotation() {
		int linear = Math.round(toLinearSpace());

		int index = linear % 12;
		Note note = Note.values()[index];

		int octave = Math.max(linear / 12 - 1, 0);

		return note.toString() + octave;
	}

	@Override
	public String toString() {
		return "Frequency: " + frequency + ", Precision: " + precision;
	}
}
